#include "log.h"
#include "config.h"
#include <map>
#include <iostream>
#include <functional>
#include <time.h>
#include <string.h>

namespace sylar {

// 日志级别的toString 方法
const char* LogLevel::ToString(LogLevel::Level level) {
  switch(level) {
#define XX(name) \
  case LogLevel::name: \
    return #name; \
    break;

  XX(DEBUG);
  XX(INFO);
  XX(WARN);
  XX(ERROR);
  XX(FATAL);
#undef XX
  default:
    return "UNKNOW";
  }
  return "UNKNOW";
}

// 通过 string 获取日志级别的方法
LogLevel::Level LogLevel::FromString(const std::string& str) {
#define XX(level, v) \
  if (str == #v) \
    return LogLevel::level 

  XX(DEBUG, debug);
  XX(INFO, info);
  XX(WARN, warn);
  XX(ERROR, error);
  XX(FATAL, fatal);

  XX(DEBUG, DEBUG);
  XX(INFO, INFO);
  XX(WARN, WARN);
  XX(ERROR, ERROR);
  XX(FATAL, FATAL);
  return LogLevel::UNKNOW;
#undef XX
}

LogEventWrap::LogEventWrap(LogEvent::ptr e)
  :m_event(e) {
}

// 析构时执行 log 方法
LogEventWrap::~LogEventWrap() {
  m_event->getLogger()->log(m_event);
}

// 函数入口
void LogEvent::format(const char* fmt, ...) {
  va_list al;
  va_start(al, fmt);
  format(fmt, al);
  va_end(al);
}

// 按照 fmt 格式格式化日志事件，并输出到 m_ss
void LogEvent::format(const char* fmt, va_list al) {
  char* buf = nullptr;
  int len = vasprintf(&buf, fmt, al);
  if(len != -1) {
    m_ss << std::string(buf, len);
    free(buf);
  }
}

std::stringstream& LogEventWrap::getSS() {
  return m_event->getSS();
}

void LogAppender::setFormatter(LogFormatter::ptr val) {
  MutexType::Lock lock(m_mutex);
  m_formatter = val;
  if (m_formatter) {
    m_hasFormatter = true;          
  } else {
    m_hasFormatter = false;                
  }     
}

LogFormatter::ptr LogAppender::getFormatter() {
  MutexType::Lock lock(m_mutex);
  return m_formatter;
}

class MessageFormatItem : public LogFormatter::FormatItem {
public:
  MessageFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getContent();
  }
};

class LevelFormatItem : public LogFormatter::FormatItem {
public:
  LevelFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << LogLevel::ToString(event->getLevel());
  }
};

class ElapseFormatItem : public LogFormatter::FormatItem {
public:
  ElapseFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getElapse();
  }
};

class NameFormatItem : public LogFormatter::FormatItem {
public:
  NameFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getLogger()->getName();
  }
};

class ThreadIdFormatItem : public LogFormatter::FormatItem {
public:
  ThreadIdFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getThreadId();
  }
};

class FiberIdFormatItem : public LogFormatter::FormatItem {
public:
  FiberIdFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getFiberId();
  }
};

class ThreadNameFormatItem : public LogFormatter::FormatItem {
public:
  ThreadNameFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getThreadName();
  }
};

class DateTimeFormatItem : public LogFormatter::FormatItem {
public:
  DateTimeFormatItem(const std::string& format = "%Y-%m-%d %H:%M:%S")
    :m_format(format) {
    if(m_format.empty()) {
      m_format = "%Y-%m-%d %H:%M:%S";
    }
  }

  // 设置时间格式并输出到 os
  void format(std::ostream& os, LogEvent::ptr event) override {
    struct tm tm;
    time_t time = event->getTime();
    localtime_r(&time, &tm);
    char buf[64];
    strftime(buf, sizeof(buf), m_format.c_str(), &tm);
    os << buf;
  }
private:
  std::string m_format;
};

class FilenameFormatItem : public LogFormatter::FormatItem {
public:
  FilenameFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getFile();
  }
};

class LineFormatItem : public LogFormatter::FormatItem {
public:
  LineFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << event->getLine();
  }
};

class NewLineFormatItem : public LogFormatter::FormatItem {
public:
  NewLineFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << std::endl;
  }
};

class StringFormatItem : public LogFormatter::FormatItem {
public:
  explicit StringFormatItem(const std::string& str)
    :m_string(str) {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << m_string;
  }
private:
  std::string m_string;
};

class TabFormatItem : public LogFormatter::FormatItem {
public:
  TabFormatItem(const std::string& str = "") {}
  void format(std::ostream& os, LogEvent::ptr event) override {
    os << "\t";
  }
private:
  std::string m_string;
};

LogEvent::LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level
        ,const char* file, int32_t line, uint32_t elapse
        , uint32_t thread_id, std::string threadName
        , uint32_t fiber_id, uint64_t time)
  :m_file(file)
  ,m_line(line)
  ,m_elapse(elapse)
  ,m_threadId(thread_id)
  ,m_threadName(threadName)
  ,m_fiberId(fiber_id)
  ,m_time(time)
  ,m_level(level) 
  ,m_logger(logger) {
}

Logger::Logger(const std::string& name)
  :m_name(name)
  ,m_level(LogLevel::DEBUG) {
  m_formatter.reset(new LogFormatter("%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"));
}

void Logger::setFormatter(LogFormatter::ptr val) {
  MutexType::Lock lock(m_mutex);
  m_formatter = val;
  // 给所有没有 formatter 的 appender 设置 formatter
  for(auto& i : m_appenders) {
    MutexType::Lock ll(i->m_mutex);
    if(!i->m_hasFormatter) {
      i->m_formatter = m_formatter;
    }
  }
}

void Logger::setFormatter(const std::string& val) {
  sylar::LogFormatter::ptr new_val(new sylar::LogFormatter(val));
  // 如果格式解析错误，则直接输出错误信息，不能添加 formatter
  if(new_val->isError()) {
    // 由于 logger 还不能自举，所以只能选择输出到 cout 或者其他库流中
    std::cout << "Logger setFormatter name=" << m_name
              << " value=" << val << " invalid formatter"
              << std::endl;
    return;
  }
  // m_formatter = new_val;
  setFormatter(new_val);
}

std::string Logger::toYamlString() {
  MutexType::Lock lock(m_mutex);
  YAML::Node node;
  node["name"] = m_name;
  if(m_level != LogLevel::UNKNOW) {
    node["level"] = LogLevel::ToString(m_level);
  }
  if(m_formatter) {
    node["formatter"] = m_formatter->getPattern();
  }

  for(auto& i : m_appenders) {
    node["appenders"].push_back(YAML::Load(i->toYamlString()));
  }
  std::stringstream ss;
  ss << node;
  return ss.str();
}

LogFormatter::ptr Logger::getFormatter() {
  MutexType::Lock lock(m_mutex);
  return m_formatter;
}

void Logger::addAppender(LogAppender::ptr appender) {
  MutexType::Lock lock(m_mutex);
  if(!appender->getFormatter()) {
    MutexType::Lock ll(appender->m_mutex);
    // 当添加的 appender 没有 formatter 的时候，将其的 formatter 设为默认的 formatter
    appender->m_formatter = m_formatter;
  }
  m_appenders.push_back(appender);
}

// 删除指定的 appender
void Logger::delAppender(LogAppender::ptr appender) {
  MutexType::Lock lock(m_mutex);
  for(auto it = m_appenders.begin();
        it != m_appenders.end(); ++it) {
      if(*it == appender) {
        m_appenders.erase(it);
        break;
      }
  }
}

void Logger::clearAppenders() {
  MutexType::Lock lock(m_mutex);
  m_appenders.clear();
}

void Logger::log(LogEvent::ptr event) {
  // 只有当 event.level 不小于 logger 的 level 时才写入日志
  if(event->getLevel() >= m_level) {
    auto self = shared_from_this();
    MutexType::Lock lock(m_mutex);
    if (!m_appenders.empty()) {
      // 将 event 写入所有的 appender
      for(auto& i : m_appenders) {
        i->log(event);
      }
    } else if(m_root) { 
      // 当当前 logger 没有 appender 时将 event 写入 m_root
      m_root->log(event);
    }
  }
}

FileLogAppender::FileLogAppender(const std::string& filename)
  :m_filename(filename) {
  reopen();
}

void FileLogAppender::log(LogEvent::ptr event) {
  if(event->getLevel() >= m_level) {
    uint64_t now = time(0);
    // 每秒 reopen 一次文件，防止日志文件被删除等情况
    if(now != m_lastTime) {
      reopen();
      m_lastTime = now;
    }
    MutexType::Lock lock(m_mutex);
    // 判断是否写入成功 
    if(!(m_filestream << m_formatter->format(event))) {
      std::cout << "error" << std::endl;
    }
  }
}

std::string FileLogAppender::toYamlString() {
  MutexType::Lock lock(m_mutex);
  YAML::Node node;
  node["type"] = "FileLogAppender";
  node["file"] = m_filename;
  if(m_level != LogLevel::UNKNOW) {
    node["level"] = LogLevel::ToString(m_level);
  }
  if(m_hasFormatter && m_formatter) {
    node["formatter"] = m_formatter->getPattern();
  }
  std::stringstream ss;
  ss << node;
  return ss.str();
}

bool FileLogAppender::reopen() {
  MutexType::Lock lock(m_mutex);
  if(m_filestream) {
    m_filestream.close();
  }
  m_filestream.open(m_filename, std::ios::app);
  return !!m_filestream;
}

void StdoutLogAppender::log(LogEvent::ptr event) {
  if(event->getLevel() >= m_level) {
    MutexType::Lock lock(m_mutex);
    std::cout << m_formatter->format(event);
  }
}

std::string StdoutLogAppender::toYamlString() {
  MutexType::Lock lock(m_mutex);
  YAML::Node node;
  node["type"] = "StdoutLogAppender";
  if(m_level != LogLevel::UNKNOW) {
    node["level"] = LogLevel::ToString(m_level);
  }
  if(m_hasFormatter && m_formatter) {
    node["formatter"] = m_formatter->getPattern();
  }
  std::stringstream ss;
  ss << node;
  return ss.str();
}

LogFormatter::LogFormatter(const std::string& pattern)
  :m_pattern(pattern) {
  // 解析 pattern，并 向 items 中按需添加解析得到的 item
  init();
}

// 通过全部的 item->format 得到要输出的一条完整的日志
std::string LogFormatter::format(LogEvent::ptr event) {
  std::stringstream ss;
  for(auto& i : m_items) {
    i->format(ss, event);
  }
  return ss.str();
}

// %xxx %xxx{xxx} %%
// 解析 pattern，并向 items 中按序添加解析得到的 item
void LogFormatter::init() {
  //str, format, type
  std::vector<std::tuple<std::string, std::string, int>> vec;
  std::string nstr;
  for(size_t i = 0; i < m_pattern.size(); ++i) {
    if(m_pattern[i] != '%') {
      nstr.append(1, m_pattern[i]);
      continue;
    }

    if((i + 1) < m_pattern.size()) {
      if(m_pattern[i + 1] == '%') {
        nstr.append(1, '%');
        continue;
      }
    }
    
    size_t n = i + 1;
    int fmt_status = 0;
    size_t fmt_begin = 0;

    std::string str;
    std::string fmt;
    while(n < m_pattern.size()) {
      if(!fmt_status && (!isalpha(m_pattern[n]) && m_pattern[n] != '{'
        && m_pattern[n] != '}')) {
        str = m_pattern.substr(i + 1, n - i - 1);
        break;
      }
      if(fmt_status == 0) {
        if(m_pattern[n] == '{') {
          str = m_pattern.substr(i + 1, n - i - 1);
          //std::cout << "*" << str << std::endl;
          fmt_status = 1; //解析格式
          fmt_begin = n;
          ++n;
          continue;
        }
      } else if(fmt_status == 1) {
        if(m_pattern[n] == '}') {
          fmt = m_pattern.substr(fmt_begin + 1, n - fmt_begin - 1);
          //std::cout << "#" << fmt << std::endl;
          fmt_status = 0;
          ++n;
          break;
        }
      }
      ++n;
      if(n == m_pattern.size()) {
        if(str.empty()) {
          str = m_pattern.substr(i + 1);
        }
      }
    }

    if(fmt_status == 0) {
      if(!nstr.empty()) {
        vec.push_back(std::make_tuple(nstr, std::string(), 0));
        nstr.clear();
      }
      vec.push_back(std::make_tuple(str, fmt, 1));
      i = n - 1;
    } else if(fmt_status == 1) {
      std::cout << "pattern parse error: " << m_pattern << " - " << m_pattern.substr(i) << std::endl;
      m_error = true;
      vec.push_back(std::make_tuple("<<pattern_error>>", fmt, 0));
    }
  }

  if(!nstr.empty()) {
    vec.push_back(std::make_tuple(nstr, "", 0));
  }
  static std::map<std::string, std::function<FormatItem::ptr(const std::string& str)> > s_format_items = {
#define XX(str, C) \
    {#str, [](const std::string& fmt) { return FormatItem::ptr(new C(fmt));}}

    // 消息
    XX(m, MessageFormatItem),
    // 日志级别
    XX(p, LevelFormatItem),
    // 累计毫秒数
    XX(r, ElapseFormatItem),
    // 日志名称
    XX(c, NameFormatItem),
    // 线程 id
    XX(t, ThreadIdFormatItem),
    // 换行符
    XX(n, NewLineFormatItem),
    // 时间
    XX(d, DateTimeFormatItem),
    // 文件名
    XX(f, FilenameFormatItem),
    // 行号
    XX(l, LineFormatItem),
    // Tab
    XX(T, TabFormatItem),
    // 协程 id
    XX(F, FiberIdFormatItem),
    // 线程名称
    XX(N, ThreadNameFormatItem),
#undef XX
  };

  for(auto& i : vec) {
    if(std::get<2>(i) == 0) {
      m_items.push_back(FormatItem::ptr(new StringFormatItem(std::get<0>(i))));
    } else {
      auto it = s_format_items.find(std::get<0>(i));
      if(it == s_format_items.end()) {
        m_items.push_back(FormatItem::ptr(new StringFormatItem("<<error_format %" + std::get<0>(i) + ">>")));
        m_error = true;
      } else {
        m_items.push_back(it->second(std::get<1>(i)));
      }
    }
  }
}

LoggerManager::LoggerManager() {
  m_root.reset(new Logger);
  m_root->addAppender(LogAppender::ptr(new StdoutLogAppender));
  m_loggers[m_root->m_name] = m_root;
}

Logger::ptr LoggerManager::getLogger(const std::string& name) {
  MutexType::Lock lock(m_mutex);
  auto it = m_loggers.find(name);
  if (it != m_loggers.end()) {
    return it->second;
  }
  Logger::ptr logger(new Logger(name));
  logger->m_root = m_root;
  m_loggers[name] = logger;
  return logger;
}

// 初始化 appender 时会用到的对象集合
struct LogAppenderDefine {
  // 1 - file, 2 - stdout
  int type = 0;
  LogLevel::Level level = LogLevel::UNKNOW;
  std::string formatter;
  std::string file;

  bool operator==(const LogAppenderDefine& oth) const {
    return type == oth.type
      && level == oth.level
      && formatter == oth.formatter
      && file == oth.file;
  }
};

// 初始化日志时会用到的对象集合
// 用于加载配置初始化日志系统
struct LogDefine {
  std::string name;
  LogLevel::Level level = LogLevel::UNKNOW;
  std::string formatter;
  std::vector<LogAppenderDefine> appenders;

  bool operator==(const LogDefine& oth) const {
    return name == oth.name 
      && level == oth.level
      && formatter == oth.formatter
      && appenders == oth.appenders;
  }
  bool operator<(const LogDefine& oth) const {
    return name < oth.name; 
  }
};

// 对 std::set<LogDefine> 的偏特化
template<>
class LexicalCast<std::string, std::set<LogDefine>> {
public:
  std::set<LogDefine> operator()(const std::string& v) {
    YAML::Node node = YAML::Load(v);
    std::set<LogDefine> vec;
    // node["name"].IsDefined()
    for(size_t i = 0; i < node.size(); ++i) {
      auto n = node[i];
      if(!n["name"].IsDefined()) {
        std::cout << "log config error: name is null, " << n
                  << std::endl;
        continue;
      }

      LogDefine ld;
      ld.name = n["name"].as<std::string>();
      ld.level = LogLevel::FromString(n["level"].IsDefined() ? n["level"].as<std::string>() : "");
      if(n["formatter"].IsDefined()) {
        ld.formatter = n["formatter"].as<std::string>();
      }

      if(n["appenders"].IsDefined()) {
        // std::cout << "==" << ld.name << " = " << n["appenders"].size() << std::endl;
        for(size_t x = 0; x < n["appenders"].size(); ++x) {
          auto a = n["appenders"][x];
          if(!a["type"].IsDefined()) {
            std::cout << "log config error: appender type is null, " << a
                      << std::endl;
            continue;
          }
          std::string type = a["type"].as<std::string>();
          LogAppenderDefine lad;
          if(type == "FileLogAppender") {
            lad.type = 1;
            if(!a["file"].IsDefined()) {
              std::cout << "log config error: fileappender file is null, " << a
                    << std::endl;
              continue;
            }
            lad.file = a["file"].as<std::string>();
            if(a["formatter"].IsDefined()) {
              lad.formatter = a["formatter"].as<std::string>();
            }
          } else if(type == "StdoutLogAppender") {
            lad.type = 2;
          } else {
            std::cout << "log config error: appender type is invalid, " << a
                      << std::endl;
            continue;
          }

          ld.appenders.push_back(lad);
        }
      }
      // std::cout << "---" << ld.name << " - "
      //           << ld.appenders.size() << std::endl;
      vec.insert(ld);
    }
    return vec;
  }
};

template<>
class LexicalCast<std::set<LogDefine>, std::string> {
public:
  std::string operator()(const std::set<LogDefine>& v) {
    YAML::Node node;
    for(auto& i : v) {
      YAML::Node n;
      n["name"] = i.name;
      if(i.level != LogLevel::UNKNOW) {
        n["level"] = LogLevel::ToString(i.level);
      }
      if(i.formatter.empty()) {
        n["formatter"] = i.formatter;
      }

      for(auto& a : i.appenders) {
        YAML::Node na;
        if(a.type == 1) {
          na["type"] = "FileLogAppender";
          na["file"] = a.file;
        } else if(a.type == 2) {
          na["type"] = "StdoutLogAppender";
        }
        if(a.level != LogLevel::UNKNOW) {
          na["level"] = LogLevel::ToString(a.level);
        }

        if(!a.formatter.empty()) {
          na["formatter"] = a.formatter;
        }

        n["appenders"].push_back(na);
      }
      node.push_back(n);
    }
    std::stringstream ss;
    ss << node;
    return ss.str();
  }
};


// 日志配置
sylar::ConfigVar<std::set<LogDefine>>::ptr g_lod_defines = 
  sylar::Config::Lookup("logs", std::set<LogDefine>(), "logs config");

struct LogIniter {
  // 通过构造函数初始化日志系统
  LogIniter() {
    g_lod_defines->addListener([](const std::set<LogDefine>& old_value, const std::set<LogDefine>& new_value) {
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "on_logger_conf_changed";
        // 新增
        for (auto &i : new_value) {
          auto it = old_value.find(i);
          sylar::Logger::ptr logger;
          if (it == old_value.end()) {
            // 新增 logger
            logger = SYLAR_LOG_NAME(i.name);
          } else {
            if (!(i == *it)) {
              // 修改的 logger
              logger = SYLAR_LOG_NAME(i.name);
            }
          }
          logger->setLevel(i.level);
          if (!i.formatter.empty()) {
            logger->setFormatter(i.formatter);             
          }

          logger->clearAppenders();
          for (auto &a : i.appenders) {
            sylar::LogAppender::ptr ap;
            if (a.type == 1) {
              ap.reset(new FileLogAppender(a.file));
            } else if (a.type == 2) {
              ap.reset(new StdoutLogAppender);
            }
            ap->setLevel(a.level);
            if (!a.formatter.empty()) {
              LogFormatter::ptr fmt(new LogFormatter(a.formatter));
              if (!fmt->isError()) {
                ap->setFormatter(fmt);
              } else {
                std:: cout << "log.name" << i.name << " appender type=" << a.type 
                           << " formatter=" << a.formatter << " is invalid" << std::endl;
              }
            }
            logger->addAppender(ap);
          }
        }

        // 删除
        for (auto &i : old_value) {
          auto it = new_value.find(i);
          if (it == new_value.end()) {
            // 删除 logger
            auto logger = SYLAR_LOG_NAME(i.name);
            // 将日志级别设置得很高，使进程无法向其中写入内容，相当于删除
            logger->setLevel((LogLevel::Level)100);
            logger->clearAppenders();
          }
        }
    });
  }
};

// 会在 main 函数之前调用 LogIniter 的构造函数
static LogIniter __log_init;

std::string LoggerManager::toYamlString() {
  MutexType::Lock lock(m_mutex);
  YAML::Node node;
  for(auto& i : m_loggers) {
    node.push_back(YAML::Load(i.second->toYamlString()));
  }
  std::stringstream ss;
  ss << node;
  return ss.str();
}

}
